﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Drawing;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Threading;

namespace BL
{
    public class cGame
    {
        public delegate void PlayerUpdateListener(int playerID);
        public event PlayerUpdateListener LocationUpdate;
        public event PlayerUpdateListener PlayerHasFlag;
        public event PlayerUpdateListener PlayerIsDead;
        public event PlayerUpdateListener PlayerReturnedFlag;
        public event PlayerUpdateListener PlayerInSpawnPoint;
        public event PlayerUpdateListener PlayerRevived;

        public cTCPConnectionHandler tcpConnectionHandler { get; set; }

        public cTeam MyTeam { get; set; }

        public cTeam EnemyTeam { get; set; }

        public int RoundsNumber { get; set; }

        public int CurrRound { get; set; }

        public int RoundTimer { get; set; }

        public int StartPort { get; set; }

        public void OnPlayerLocationUpdated(cTeam team, cPlayer player)
        {
            if (LocationUpdate != null)
                LocationUpdate(player.ID);
        }

        public bool UpdateEnemyInfo(int port, string IP)
        {
            byte[] data = null;
            if (tcpConnectionHandler == null)
                if (!ConnectToEnemy(IP, port))
                    return false;    
            tcpConnectionHandler.SendData(Serialize(MyTeam));
            do
            {
                Thread.Sleep(500);
                data = tcpConnectionHandler.ReceiveData();
            } while (data == null);

            EnemyTeam = (cTeam)Deserialize(data);
            EnemyTeam.RefreshAllConnections(StartPort);
            EnemyTeam.PlayerLocationUpdate += new cTeam.PlayerUpdateListener(OnPlayerLocationUpdated);
            EnemyTeam.PlayerHasFlag += new cTeam.PlayerUpdateListener(OnPlayerHasFlag);
            EnemyTeam.PlayerIsDead += new cTeam.PlayerUpdateListener(OnPlayerIsDead);
            EnemyTeam.PlayerReturnedFlag += new cTeam.PlayerUpdateListener(OnPlayerReturnedFlag);
            EnemyTeam.PlayerInSpawnPoint += new cTeam.PlayerUpdateListener(OnPlayerInSpawnPoint);
            EnemyTeam.PlayerRevived += new cTeam.PlayerUpdateListener(OnPlayerRevived);

            return true;
        }

        private void OnPlayerRevived(cTeam team, cPlayer player)
        {
            if (PlayerRevived != null)
                PlayerRevived(player.ID);
        }

        private void OnPlayerInSpawnPoint(cTeam team, cPlayer player)
        {
            if (PlayerInSpawnPoint != null)
                PlayerInSpawnPoint(player.ID);
        }

        private void OnPlayerReturnedFlag(cTeam team, cPlayer player)
        {
            if (PlayerReturnedFlag != null)
                PlayerReturnedFlag(player.ID);
        }

        private bool ConnectToEnemy(string IP, int port)
        {
            tcpConnectionHandler = new cTCPConnectionHandler();
            StartPort = port;
            int tryNum = 0;
            while ((tryNum < 3) && (!tcpConnectionHandler.Connect(IP, StartPort)))
                tryNum++;
            if ((tcpConnectionHandler.Client == null) || (!tcpConnectionHandler.Client.Connected))
                tcpConnectionHandler.StartListening(StartPort);
            if (tcpConnectionHandler.Client != null)
                return tcpConnectionHandler.Client.Connected;
            return false;
        }

        private byte[] Serialize(object obj)
        {
            MemoryStream stream = new MemoryStream();
            BinaryFormatter serializer = new BinaryFormatter();
            serializer.Serialize(stream, obj);
            return stream.ToArray();
        }

        private object Deserialize(byte[] data)
        {
            MemoryStream stream = new MemoryStream();
            BinaryFormatter serializer = new BinaryFormatter();
            stream.Write(data, 0, data.Count());
            stream.Position = 0;
            return serializer.Deserialize(stream);
        }

        public void SetTeam(cTeam team)
        {
            MyTeam = team;
            MyTeam.PlayerLocationUpdate += new cTeam.PlayerUpdateListener(OnPlayerLocationUpdated);
            MyTeam.PlayerHasFlag += new cTeam.PlayerUpdateListener(OnPlayerHasFlag);
            MyTeam.PlayerIsDead += new cTeam.PlayerUpdateListener(OnPlayerIsDead);
            MyTeam.PlayerReturnedFlag += new cTeam.PlayerUpdateListener(OnPlayerReturnedFlag);
            MyTeam.PlayerInSpawnPoint += new cTeam.PlayerUpdateListener(OnPlayerInSpawnPoint);
            MyTeam.PlayerRevived += new cTeam.PlayerUpdateListener(OnPlayerRevived);
        }

        private void OnPlayerIsDead(cTeam team, cPlayer player)
        {
            if (PlayerIsDead != null)
                PlayerIsDead(player.ID);
        }

        private void OnPlayerHasFlag(cTeam team, cPlayer player)
        {
            if (PlayerHasFlag != null)
                PlayerHasFlag(player.ID);
        }
    }
}
